package com.bootdo.rabbitMQ.aspect;


import com.alibaba.fastjson.JSON;
import com.bootdo.common.utils.IpAddressUtil;
import com.bootdo.rabbitMQ.config.RabbitConstant;
import com.bootdo.rabbitMQ.entity.MessageVo;
import com.bootdo.rabbitMQ.entity.News;
import com.bootdo.rabbitMQ.producer.Sender;
import com.mysql.cj.util.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author wukq
 * @Date: 2020/4/14
 * @Description:
 */
@Aspect
@Component
public class WebRabbitLogAspect {

    ThreadLocal<Long> startTime = new ThreadLocal<>();
    ThreadLocal<String> classMethod = new ThreadLocal<>();
    @Autowired
    private Sender sender;
    private Logger logger = LoggerFactory.getLogger(getClass());

    //  修饰符匹配（modifier-pattern?）
    //  返回值匹配（ret-type-pattern）可以为*表示任何返回值,全路径的类名等
    //  类路径匹配（declaring-type-pattern?）
    //  方法名匹配（name-pattern）可以指定方法名 或者 *代表所有, set* 代表以set开头的所有方法
    //  参数匹配（(param-pattern)）可以指定具体的参数类型，多个参数间用“,”隔开，各个参数也可以用“*”来表示匹配任意类型的参数，
    // 如(String)表示匹配一个String参数的方法；(*,String) 表示匹配有两个参数的方法，第一个参数可以是任意类型，而第二个参数是String类型；
    // 可以用(..)表示零个或多个任意参数
    //  异常类型匹配（throws-pattern?）
    //  其中后面跟着“?”的是可选项

    // 定义切入点  @Pointcut("execution(public * com.jay..*.*(..))")  -- 表示对com.jay 包下的所有方法都可添加切入点
    @Pointcut("execution(public * com.bootdo.*.*.controller..*.*(..))")
    @Order(-1)
    public void webLog() {
    }

    @Pointcut("execution(public * com.bootdo.*.*.*.controller..*.*(..))")
    @Order(1)
    public void mobileLog() {
    }

    @Pointcut("execution(public * com.bootdo.*.*.*.*.controller..*.*(..))")
    @Order(2)
    public void mobileWorkerLog() {
    }

    @Pointcut("execution(public * com.bootdo.*.controller..*.*(..))")
    @Order(3)
    public void commonLog() {
    }

    @Before("webLog() || mobileLog() || mobileWorkerLog() || commonLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        logger.info("URL : " + request.getRequestURL().toString() + " ,HTTP_METHOD : " + request.getMethod() + " , IP : " + IpAddressUtil.getIp(request));
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        classMethod.set(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        startTime.set(System.currentTimeMillis());

    }

    @AfterReturning(returning = "ret", pointcut = "webLog() || mobileLog() || mobileWorkerLog() || commonLog()")
    public Object doAfterReturning(Object ret) throws Throwable {
        //处理时间
        logger.info("CLASS_METHOD : " + classMethod.get() + ", SPEND TIME : " + (System.currentTimeMillis() - startTime.get()) + " ms");
        // 处理完请求，返回内容
        //logger.info("RESPONSE : " + ret);
        return ret;
    }


    @Pointcut(value = "execution(public * com.bootdo.rabbitMQ.service..*.*(..))")
    public void pointCut() {

    }

    /**
     * direct路由交换机测试
     */
    @Around("pointCut() && @annotation(com.bootdo.rabbitMQ.annos.RabbitmqTag) ")
    public Object around(ProceedingJoinPoint joinPoint) {
        try {

            Object[] paramValues = joinPoint.getArgs();
            //String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
            Object object = joinPoint.proceed(); //执行目标方法
            Object paramValue = paramValues[0];

            List<News> messageList = new ArrayList<>();
            if (paramValue instanceof List) {
                messageList = (List<News>) paramValues[0];
            } else if (paramValue instanceof News) {
                messageList.add((News) paramValues[0]);
            }

            if (messageList != null && messageList.size() > 0) {
                for (News item : messageList) {
                    Integer msgInfoType = item.getMsgInfoType();// 1- 推送,2-短信
                    String msgInfo = JSON.toJSONString(item);
                    logger.info("发送消息内容:" + msgInfo);
                    if (msgInfoType == null) {
                        continue;
                    }
                    MessageVo messageVo = new MessageVo();
                    messageVo.setMsg(msgInfo);//msginfo是一个json形式的字符串
                    messageVo.setReceiveUserId(null);
                    if (null != msgInfoType && msgInfoType.equals(1)) {
                        messageVo.setRoutingKey(RabbitConstant.RK_MESSAGE_PUSH);
                    } else if (null != msgInfoType && msgInfoType.equals(2)) {
                        messageVo.setRoutingKey(RabbitConstant.RK_SMS_PUSH);
                    }
                    if (!StringUtils.isNullOrEmpty(messageVo.getRoutingKey())) {
                        sender.send(messageVo);
                    }
                }
            } else {
                logger.error("发送消息内容为空...");
                return object;
            }

            return object;
        } catch (Throwable throwable) {
            logger.error("执行Rabbimq消息失败:" + throwable.getMessage());
            throwable.printStackTrace();
        }
        return null;
    }


}
